package com.ruoyi.business.service.impl;

import com.ruoyi.business.constant.IBusinessConstant;
import com.ruoyi.business.domain.*;
import com.ruoyi.business.domain.sqldesign.SqlDesignModel;
import com.ruoyi.business.domain.sqldesign.TableModel;
import com.ruoyi.business.mapper.*;
import com.ruoyi.business.service.IExtBusinessFunctionService;
import com.ruoyi.business.service.IExtInterfaceSearchPersonalizedService;
import com.ruoyi.business.service.IExtInterfaceService;
import com.ruoyi.business.utils.TemplateHelper;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.security.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 接口Service业务层处理
 *
 * @author ruoyi
 * @date 2024-01-08
 */
@Service
@Slf4j
public class ExtInterfaceServiceImpl implements IExtInterfaceService
{
    @Autowired
    private ExtInterfaceMapper extInterfaceMapper;
    @Autowired
    private ExtModelDatasourceMapper extModelDatasourceMapper;
    @Autowired
    private ExtInterfaceBusinessFunctionRelaMapper extInterfaceBusinessFunctionRelaMapper;
    @Autowired
    private ExtInterfaceParameterMapper extInterfaceParameterMapper;
    @Autowired
    private ExtInterfaceParameterRelaMapper extInterfaceParameterRelaMapper;
    @Autowired
    private ExtInterfaceReturnValueMapper extInterfaceReturnValueMapper;
    @Autowired
    private ExtInterfaceReturnValueRelaMapper extInterfaceReturnValueRelaMapper;
    @Autowired
    private ExtBusinessFunctionMapper extBusinessFunctionMapper;
    @Autowired
    private IExtBusinessFunctionService extBusinessFunctionService;
    @Autowired
    private IExtInterfaceSearchPersonalizedService extInterfaceSearchPersonalizedService;
    /**
     * 查询接口
     *
     * @param id 接口主键
     * @return 接口
     */
    @Override
    public ExtInterface selectExtInterfaceById(Long id)
    {
        return extInterfaceMapper.selectExtInterfaceById(id);
    }

    /**
     * 查询接口列表
     *
     * @param extInterface 接口
     * @return 接口
     */
    @Override
    public List<ExtInterface> selectExtInterfaceList(ExtInterface extInterface)
    {
        return extInterfaceMapper.selectExtInterfaceList(extInterface);
    }

    /**
     * 新增接口
     *
     * @param extInterface 接口
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertExtInterface(ExtInterface extInterface)
    {
        //插入前校验
        checkInsert(extInterface);
        //插入业务功能和接口关系表
        ExtInterfaceBusinessFunctionRela extInterfaceBusinessFunction = new ExtInterfaceBusinessFunctionRela();
        extInterfaceBusinessFunction.setInterfaceCode(extInterface.getInterfaceCode());
        extInterfaceBusinessFunction.setBusinessCode(extInterface.getBusinessCode());
        extInterfaceBusinessFunction.setCreateTime(DateUtils.getNowDate());
        extInterfaceBusinessFunction.setCreateBy(SecurityUtils.getUsername());
        extInterfaceBusinessFunction.setEnterpriseCode(extInterface.getEnterpriseCode());
        extInterfaceBusinessFunction.setApplicationCode(extInterface.getApplicationCode());
        extInterfaceBusinessFunctionRelaMapper.insertExtInterfaceBusinessFunctionRela(extInterfaceBusinessFunction);
        int rownum=  extInterfaceMapper.insertExtInterface(extInterface);
        //接口类型为查询时，则调用查询接口个性化表服务进行插入（把接口id传入)
        if(IBusinessConstant.INTERFACE_TYPE_SEARCH.equals(extInterface.getInterfaceType())) {
            ExtInterfaceSearchPersonalized searchPersonalizedVo = new ExtInterfaceSearchPersonalized();
            searchPersonalizedVo.setExtInterfaceId(extInterface.getId());
            searchPersonalizedVo.setDesignSql(extInterface.getDesignSql());
            searchPersonalizedVo.setProduceSql(extInterface.getProduceSql());
            searchPersonalizedVo.setCreateTime(DateUtils.getNowDate());
            searchPersonalizedVo.setCreateBy(SecurityUtils.getUsername());
            searchPersonalizedVo.setEnterpriseCode(extInterface.getEnterpriseCode());
            searchPersonalizedVo.setApplicationCode(extInterface.getApplicationCode());
            extInterfaceSearchPersonalizedService.insertExtInterfaceSearchPersonalized(searchPersonalizedVo);
        }
        return rownum;
    }

    /**
     * 插入前校验
     * @param extInterface
     */
    private void checkInsert(ExtInterface extInterface) {
        if(extInterface==null)
            throw new ServiceException("插入对象为空!");
        //接口名称不能为空
        if(StringUtils.isEmpty(extInterface.getInterfaceName()))
            throw new ServiceException("接口名称不能为空!");
        Map<String,Object> searchMap = new HashMap<>();
        //接口名称不能重复
        searchMap.put("interfaceName",extInterface.getInterfaceName());
        if(extInterfaceMapper.selectCount(searchMap)>0)
            throw new ServiceException("接口名称:"+extInterface.getInterfaceName()+"已经存在!");
        //接口编码不能为空
        if(StringUtils.isEmpty(extInterface.getInterfaceCode()))
            throw new ServiceException("接口编码不能为空!");
        //接口编码不能重复
        searchMap.clear();
        searchMap.put("interfaceCode",extInterface.getInterfaceCode());
        if(extInterfaceMapper.selectCount(searchMap)>0)
            throw new ServiceException("接口编码:"+extInterface.getInterfaceCode()+"已经存在!");
        //接口url不能为空
        if(StringUtils.isEmpty(extInterface.getInterfaceUrl()))
            throw new ServiceException("接口url不能为空");
        //接口url不能重复
        searchMap.clear();
        searchMap.put("interfaceUrl",extInterface.getInterfaceUrl());
//        if(extInterfaceMapper.selectCount(searchMap)>0)
//            throw new ServiceException("接口url:"+extInterface.getInterfaceUrl()+"已经存在!");
        //接口类型不能为空
        if(StringUtils.isEmpty(extInterface.getInterfaceType()))
            throw new ServiceException("接口类型不能为空!");
        //接口方法不能为空
        if(StringUtils.isEmpty(extInterface.getInterfaceMethod()))
            throw new ServiceException("接口方法不能为空");
        //如果是通用url，则是否选数据源必须为是，数据源名称不能为空,且必须存在
        if(IBusinessConstant.SYSTEM_YES.equals(extInterface.getIsCommonUrl())){
            if(!IBusinessConstant.SYSTEM_YES.equals(extInterface.getIsSelectDatasource()))
                throw new ServiceException("如果是通用url，则是否选数据源必须为是");
            if(StringUtils.isEmpty(extInterface.getInterfaceDatasourceName()))
                throw new ServiceException("如果是通用url，接口数据源不能为空!");
            Map<String,Object> searchDsMap = new HashMap<>();
            searchDsMap.put("datasourceName",extInterface.getInterfaceDatasourceName());
            if(extModelDatasourceMapper.selectCount(searchDsMap)==0)
                throw new ServiceException("数据源名称:"+extInterface.getInterfaceDatasourceName()+"不存在!");
        }
        //业务编码不能为空，且必须存在
        if(StringUtils.isEmpty(extInterface.getBusinessCode()))
            throw new ServiceException("业务编码不能为空!");
        Map<String,Object> searchFunctionMap = new HashMap<>();
        searchFunctionMap.put("businessCode",extInterface.getBusinessCode());
        if(extBusinessFunctionMapper.selectCount(searchFunctionMap)==0)
            throw new ServiceException("业务编码:"+extInterface.getBusinessCode()+"不存在!");
        //接口类型为查询时，则查询sql设计JSON及产生sql不能为空
//        if(IBusinessConstant.INTERFACE_TYPE_SEARCH.equals(extInterface.getInterfaceType())){
//            if(StringUtils.isEmpty(extInterface.getDesignSql())||StringUtils.isEmpty(extInterface.getProduceSql()))
//                throw new ServiceException("接口类型为查询时,查询sql设计json及产生sql不能为空！");
//        }
    }

    /**
     * 修改接口
     *
     * @param extInterface 接口
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateExtInterface(ExtInterface extInterface)
    {

         //修改前校验
         checkUpdate(extInterface);
         //更新外部接口信息
         int rowNum =  extInterfaceMapper.updateExtInterface(extInterface);
        //接口类型为查询时，则调用查询接口个性化表服务进行插入或更新（把接口id传入)
        if(IBusinessConstant.INTERFACE_TYPE_SEARCH.equals(extInterface.getInterfaceType())) {
            ExtInterfaceSearchPersonalized searchPersonalizedVo = null;
            ExtInterfaceSearchPersonalized queryPersonalizedVo = new ExtInterfaceSearchPersonalized();
            queryPersonalizedVo.setExtInterfaceId(extInterface.getId());
            List<ExtInterfaceSearchPersonalized> list = extInterfaceSearchPersonalizedService.selectExtInterfaceSearchPersonalizedList(queryPersonalizedVo);
            if(CollectionUtils.isEmpty(list)) {
                searchPersonalizedVo = new ExtInterfaceSearchPersonalized();
                searchPersonalizedVo.setExtInterfaceId(extInterface.getId());
                searchPersonalizedVo.setDesignSql(extInterface.getDesignSql());
                searchPersonalizedVo.setProduceSql(extInterface.getProduceSql());
                searchPersonalizedVo.setCreateTime(DateUtils.getNowDate());
                searchPersonalizedVo.setCreateBy(SecurityUtils.getUsername());
                extInterfaceSearchPersonalizedService.insertExtInterfaceSearchPersonalized(searchPersonalizedVo);
            }else{
                searchPersonalizedVo = list.get(0);
                searchPersonalizedVo.setDesignSql(extInterface.getDesignSql());
                searchPersonalizedVo.setProduceSql(extInterface.getProduceSql());
                searchPersonalizedVo.setUpdateBy(SecurityUtils.getUsername());
                searchPersonalizedVo.setUpdateTime(DateUtils.getNowDate());
                extInterfaceSearchPersonalizedService.updateExtInterfaceSearchPersonalized(searchPersonalizedVo);
            }

        }
         return rowNum;

     }

    /**
     * 修改前校验
     * @param extInterface
     */
    private void checkUpdate(ExtInterface extInterface) {
        if(extInterface==null)
            throw new ServiceException("插入对象为空!");
        if(extInterface.getId()==null||extInterface.getId()==0L)
            throw new ServiceException("缺少id");
        //接口名称不能为空
        if(StringUtils.isEmpty(extInterface.getInterfaceName()))
            throw new ServiceException("接口名称不能为空!");
        Map<String,Object> searchMap = new HashMap<>();
        //接口名称不能重复
        searchMap.put("interfaceName",extInterface.getInterfaceName());
        searchMap.put("notId",extInterface.getId());
        if(extInterfaceMapper.selectCount(searchMap)>0)
            throw new ServiceException("接口名称:"+extInterface.getInterfaceName()+"已经存在!");
        //接口编码不能为空
        if(StringUtils.isEmpty(extInterface.getInterfaceCode()))
            throw new ServiceException("接口编码不能为空!");
        //接口编码不能重复
        searchMap.clear();
        searchMap.put("interfaceCode",extInterface.getInterfaceCode());
        searchMap.put("notId",extInterface.getId());
        if(extInterfaceMapper.selectCount(searchMap)>0)
            throw new ServiceException("接口编码:"+extInterface.getInterfaceCode()+"已经存在!");
        //接口url不能为空
        if(StringUtils.isEmpty(extInterface.getInterfaceUrl()))
            throw new ServiceException("接口url不能为空");
        //接口url不能重复
        searchMap.clear();
//        searchMap.put("interfaceUrl",extInterface.getInterfaceUrl());
//        searchMap.put("notId",extInterface.getId());
//        if(extInterfaceMapper.selectCount(searchMap)>0)
//            throw new ServiceException("接口url:"+extInterface.getInterfaceUrl()+"已经存在!");
        //接口类型不能为空
        if(StringUtils.isEmpty(extInterface.getInterfaceType()))
            throw new ServiceException("接口类型不能为空!");
        //接口方法不能为空
        if(StringUtils.isEmpty(extInterface.getInterfaceMethod()))
            throw new ServiceException("接口方法不能为空");
        //如果是通用url，则是否选数据源必须为是，数据源名称不能为空,且必须存在
        if(IBusinessConstant.SYSTEM_YES.equals(extInterface.getIsCommonUrl())){
            if(!IBusinessConstant.SYSTEM_YES.equals(extInterface.getIsSelectDatasource()))
                throw new ServiceException("如果是通用url，则是否选数据源必须为是");
            if(StringUtils.isEmpty(extInterface.getInterfaceDatasourceName()))
                throw new ServiceException("如果是通用url，接口数据源不能为空!");
            Map<String,Object> searchDsMap = new HashMap<>();
            searchDsMap.put("datasourceName",extInterface.getInterfaceDatasourceName());
            if(extModelDatasourceMapper.selectCount(searchDsMap)==0)
                throw new ServiceException("数据源名称:"+extInterface.getInterfaceDatasourceName()+"不存在!");
        }
        //业务编码不能为空，且必须存在
        if(StringUtils.isEmpty(extInterface.getBusinessCode()))
            throw new ServiceException("业务编码不能为空!");
        Map<String,Object> searchFunctionMap = new HashMap<>();
        searchFunctionMap.put("businessCode",extInterface.getBusinessCode());
        if(extBusinessFunctionMapper.selectCount(searchFunctionMap)==0)
            throw new ServiceException("业务编码:"+extInterface.getBusinessCode()+"不存在!");
        //接口类型为查询时,且为通用url，则查询sql设计JSON及产生sql不能为空
        if(IBusinessConstant.INTERFACE_TYPE_SEARCH.equals(extInterface.getInterfaceType()) && IBusinessConstant.SYSTEM_YES.equals(extInterface.getIsCommonUrl())){
            if(StringUtils.isEmpty(extInterface.getDesignSql())||StringUtils.isEmpty(extInterface.getProduceSql()))
                throw new ServiceException("接口类型为查询时,查询sql设计json及产生sql不能为空！");
        }
    }

    /**
     * 批量删除接口
     *
     * @param ids 需要删除的接口主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteExtInterfaceByIds(Long[] ids)
    {
        int sum =0;

        for(Long id:ids) {
            sum +=deleteExtInterfaceById(id);
        }
        return sum;
    }

    /**
     * 删除接口信息
     *
     * @param id 接口主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteExtInterfaceById(Long id)
    {
        ExtInterface extInterface = selectExtInterfaceById(id);
        if(extInterface==null)
            throw  new ServiceException("记录id："+id+"不存在!");
        //删除接口功能关系表
        extInterfaceBusinessFunctionRelaMapper.deleteByInterfaceCodeAndBusinessCode(extInterface.getInterfaceCode(),extInterface.getBusinessCode());
        //删除接口参数表
        extInterfaceParameterMapper.deleteByInterfaceCode(extInterface.getInterfaceCode());
        //删除接口参数关系表
        extInterfaceParameterRelaMapper.deleteByInterfaceCode(extInterface.getInterfaceCode());
        //删除接口返回值表
        extInterfaceReturnValueMapper.deleteByInterfaceCode(extInterface.getInterfaceCode());
        //删除接口返回值关系表
        extInterfaceReturnValueRelaMapper.deleteByInterfaceCode(extInterface.getInterfaceCode());
        //删除接口记录
        return extInterfaceMapper.deleteExtInterfaceById(id);
    }

    /**
     * 查询接口树列表
     *
     * @param extInterface
     * @return
     */
    @Override
    public List<BusinessFunctionTree> treeList(ExtInterface extInterface) {
        ExtBusinessFunction extBusinessFunction = new ExtBusinessFunction();
        List<BusinessFunctionTree> tree = extBusinessFunctionService.selectCommonBusinessFunctionTree(extBusinessFunction);
        //查询接口列表
        List<ExtInterface> extInterfaceList = extInterfaceMapper.selectInterfaceListAssignBusinessFunction(extInterface);
        fillTreeWithInterfaceList(tree,extInterfaceList);
        return tree;

    }

    /**
     * 产生sql
     *
     * @param sqlDesignModel
     * @return
     */
    @Override
    public String generateSql(SqlDesignModel sqlDesignModel) throws Exception {
        //验证数据有效性
        verifyDesignModel(sqlDesignModel);
//        File f = new File(IBusinessConstant.SELECT_TPL_PATH);
//        String sqlTpl = FileUtils.readFileToString(f, IBusinessConstant.ENCODE_UTF_8);
        String sqlTpl  = readTplFromClassPath(IBusinessConstant.SELECT_TPL_PATH);
        //调用freemark 生成sql
        return TemplateHelper.createContentByString(sqlDesignModel,sqlTpl,IBusinessConstant.ENCODE_UTF_8);
    }

    /**
     * 从类路径读取文件
     * @param selectTplPath
     * @return
     */
    private String readTplFromClassPath(String selectTplPath) throws IOException {
        try (InputStream inputStream = ExtInterfaceServiceImpl.class.getClassLoader().getResourceAsStream(selectTplPath);
             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {

            StringBuilder contentBuilder = new StringBuilder();
            String line;

            // 逐行读取文件内容
            while ((line = reader.readLine()) != null) {
                contentBuilder.append(line).append(System.lineSeparator());
            }

            String fileContent = contentBuilder.toString();
//            System.out.println(fileContent);
            return fileContent;

        } catch (Exception e) {
            e.printStackTrace();
            log.error("读取文件:"+selectTplPath+"失败!",e);
            throw e;
        }
    }

    /**
     * 验证sql设计模型
     * @param sqlDesignModel
     */
    private void verifyDesignModel(SqlDesignModel sqlDesignModel) {
        if(sqlDesignModel==null)
            throw new ServiceException("模型对象为空!");

        if(CollectionUtils.isEmpty(sqlDesignModel.getTablesModel()))
            throw new ServiceException("表模型为空!");
        List <String> tableAliasList = new ArrayList<>();
        List<String> tableOrgNameList = new ArrayList<>();
        for(TableModel tableModel:sqlDesignModel.getTablesModel()){
            if(StringUtils.isEmpty(tableModel.getEnName()))
               throw new ServiceException("表名不能为空!");
            //表别名不能重复
            if(!StringUtils.isEmpty(tableModel.getAlias())) {
                if (tableAliasList.contains(tableModel.getAlias()))
                    throw new ServiceException("表别名不能重复!");
                tableAliasList.add(tableModel.getAlias());
            }else{
                //如果表别名没有设置，则检查源表名不能重复
                if(tableOrgNameList.contains(tableModel.getEnName())){
                    throw new ServiceException("表名不能重复!");
                }
                tableOrgNameList.add(tableModel.getEnName());
            }
        }
    }

    /**
     * 使用接口填充业务功能树
     * @param tree
     * @param extInterfaceList
     */
    private void fillTreeWithInterfaceList(List<BusinessFunctionTree> tree, List<ExtInterface> extInterfaceList) {
        for(BusinessFunctionTree node:tree){
            recursionFillTree(node,extInterfaceList);
        }
    }

    /**
     * 递归填充树节点
     * @param node 树节点
     * @param extInterfaceList
     */
    private void recursionFillTree(BusinessFunctionTree node, List<ExtInterface> extInterfaceList) {
        //如果有下级节点，则递归下级，直到没有下级
        if(node.getChildren()!=null && node.getChildren().size()>0){
            for(BusinessFunctionTree child:node.getChildren()){
                recursionFillTree(child,extInterfaceList);
            }
        }else{
            //查询属于当前业务编码的接口列表
            List<ExtInterface> childList = extInterfaceList.stream().filter(extInterface -> extInterface.getBusinessCode().equals(node.getValue())).collect(Collectors.toList());
            node.setChildren(toBusinessFunctionTreeList(node.getValue(),childList));
        }
    }

    /**
     * 转换接口列表为业务功能树列表
     *
     * @param parentCode
     * @param childList
     * @return
     */
    private List<BusinessFunctionTree> toBusinessFunctionTreeList(String parentCode, List<ExtInterface> childList) {
        List<BusinessFunctionTree> retList = new ArrayList<>();
        childList.forEach(extInterface -> {
            BusinessFunctionTree businessFunctionTree = new BusinessFunctionTree();
            businessFunctionTree.setValue(extInterface.getInterfaceCode());
            businessFunctionTree.setLabel(extInterface.getInterfaceName());
            businessFunctionTree.setParentCode(parentCode);
            retList.add(businessFunctionTree);
        });
        return retList;
    }
}
